package service

import (
	"gobase/app/model"
	"gobase/util"
	"strconv"

	"github.com/casbin/casbin"

	"github.com/pkg/errors"

	"github.com/Sirupsen/logrus"
	"github.com/gin-gonic/gin"
	"github.com/xormplus/xorm"
)

type UserService struct {
	dao *xorm.Engine
	log *logrus.Logger
	ce  *casbin.Enforcer
}

//初始化方法
func NewUserService(c *gin.Context) *UserService {
	return &UserService{dao: util.GetDb(c), log: util.GetLog(c), ce: util.GetCasbin(c)}
}

//用户列表
func (uSrv *UserService) QueryList(p *util.Page, username string, orgid string) (*util.Page, []map[string]string) {
	db := uSrv.dao
	var resultp *util.Page = util.NewPage(p)
	var userList []map[string]string
	var sql = "select ### from user as t left join org as o on o.id=t.orgid "
	var wheres = []util.SqlWhere{}

	if username != "" {
		wheres = append(wheres, util.NewSqlWhere("t.username", username+"%", "like", false))
	}
	if orgid != "" {
		wheres = append(wheres, util.NewSqlWhere("t.orgid", orgid, "=", false))
	}
	countSQL, listSQL, args := util.GenSql(sql, "t.*, ifnull(o.name,'') as orgname", wheres)

	//查询总数
	total, err := db.SQL(countSQL, args...).Count(new(model.User))
	if err != nil {
		uSrv.log.Errorf("UserService->QueryList 查询错误：%s", err)
		return resultp, userList
	}

	//计算分页
	resultp.SetCount(int(total), resultp.GetPageSize())
	//查询列表
	userList, err = db.SQL(listSQL, args...).Desc("t.id").Limit(resultp.GetPageParam()).QueryString()
	if err != nil {
		uSrv.log.Errorf("UserService->QueryList 查询错误：%s", err)
	}

	return resultp, userList
}

//新增用户
func (uSrv *UserService) Add(user *model.User, roleIds []string) error {
	//判断用户名是否被使用
	exist := uSrv.IsExist(user.Username, 0)
	if exist {
		return errors.New("[" + user.Username + "]用户名已被使用!")
	} else {
		session := uSrv.dao.NewSession()
		defer session.Close()
		if err1 := session.Begin(); err1 != nil {
			return errors.Wrap(err1, "开启事务错误!")
		}

		user.Password = util.Md5Pwd(user.Password)
		newID, err := session.Insert(user)
		if err != nil {
			return errors.Wrap(err, "添加用户失败!")
		}
		if insertSQL := uSrv.getRoleUserSql(newID, roleIds); len(insertSQL) > 0 {
			_, err = session.Sql(insertSQL).Execute()
			if err != nil {
				session.Rollback()
				return errors.Wrap(err, "保存关联角色失败!")
			}
		}
		err = session.Commit()
		if err != nil {
			return errors.Wrap(err, "提交事务失败!")
		}

		//Casbin给用户添加角色
		util.AddRolesForUser(uSrv.ce, newID, roleIds)
	}
	return nil
}

//更新用户信息
func (uSrv *UserService) Update(id int64, user *model.User) error {
	exist := uSrv.IsExist(user.Username, id)
	if exist {
		return errors.New("[" + user.Username + "]用户名已被使用!")
	} else {
		session := uSrv.dao.NewSession()
		defer session.Close()
		if err1 := session.Begin(); err1 != nil {
			return errors.Wrap(err1, "开启事务错误")
		}

		_, err := session.Id(id).Cols("gender,email,phone,state").Update(user)
		if err != nil {
			session.Rollback()
			return errors.Wrap(err, "更新保存失败！")
		}
		_, err = session.Sql("delete from role_user where userid=?", id).Execute()
		if err != nil {
			session.Rollback()
			return errors.Wrap(err, "删除用户已关联角色失败！")
		}

		if err = session.Commit(); err != nil {
			return errors.Wrap(err, "事务提交失败!")
		}
	}
	return nil
}

//删除用户信息
func (uSrv *UserService) DeleteById(id int64) error {
	if id == 1 {
		return errors.New("超级管理员用户无法删除!")
	}

	session := uSrv.dao.NewSession()
	defer session.Close()
	if err := session.Begin(); err != nil {
		return errors.Wrap(err, "开启事务失败!")
	}

	_, err1 := session.SQL("delete from role_user where userid=?", id).Execute()
	if err1 != nil {
		session.Rollback()
		return errors.Wrap(err1, "删除用户角色失败!")
	}
	_, err := session.Id(id).Delete(new(model.User))
	if err != nil {
		session.Rollback()
		return errors.Wrap(err, "删除用户失败!")
	}
	//casbin 同步策略
	uidStr := strconv.FormatInt(id, 10)
	uSrv.ce.DeleteUser(uidStr)

	err = session.Commit()
	if err != nil {
		return errors.Wrap(err, "提交事务失败!")
	}
	return nil
}

//启用/禁用
func (uSrv *UserService) EnableOrDisable(id int64, state string) error {
	//禁止禁用admin
	if id == 1 && state == "0" {
		return errors.New("超级管理员用户无法禁用!")
	}

	updateSQL := "update user set state=? where id=? "
	_, err := uSrv.dao.Sql(updateSQL, state, id).Execute()
	if err != nil {
		return errors.Wrap(err, "更新用户状态失败!")
	}
	return nil
}

//根据ID查询一条记录
func (uSrv *UserService) GetByID(id int64) (model.User, error) {
	var user model.User
	_, err := uSrv.dao.Sql("select * from user t where t.id=?", id).Get(&user)
	if err != nil {
		return user, errors.Wrap(err, "获取用户信息失败!")
	}
	return user, nil
}

//根据ID查询一条记录 map返回值
func (uSrv *UserService) GetMapByID(id int64) (map[string]string, error) {
	var user = make(map[string]string)
	_, err := uSrv.dao.Sql("select t.*,ifnull(o.name,'') as orgname from user t left join org as o on o.id=t.orgid where t.id=?", id).Get(&user)
	if err != nil {
		return user, errors.Wrap(err, "获取用户map信息失败!")
	} else {
		//置空密码，防止被Http劫持
		user["password"] = ""
	}
	return user, nil
}

//判断用户名是否被使用
func (uSrv *UserService) IsExist(username string, id int64) bool {
	var exist bool
	var err error
	sql := "select * from user t where t.username=? "
	if id > 0 {
		sql = sql + " and t.id<>? "
		exist, err = uSrv.dao.SQL(sql, username, id).Exist()
	} else {
		exist, err = uSrv.dao.SQL(sql, username).Exist()
	}

	if err != nil {
		uSrv.log.Errorf("UserService->IsExist 判断用户信息是否存在错误：%s", err)
	}
	return exist
}

//根据userId 获取用户编号
func (uSrv *UserService) Login(uname string, pwd string) (bool, model.User) {
	var user model.User
	newPwd := util.Md5Pwd(pwd)
	exist, err := uSrv.dao.Sql("select * from user t where t.username=? and t.password=?", uname, newPwd).Get(&user)

	if err != nil {
		uSrv.log.Errorf("UserService->Login 登录方法错误：%s", err)
	}

	return exist, user
}

//修改登录密码
func (uSrv *UserService) ChangePwd(uid int64, oldpwd string, newpwd string) error {
	user, err := uSrv.GetByID(uid)
	if err != nil {
		return errors.Wrap(err, "用户不存在!")
	}
	if user.Password != util.Md5Pwd(oldpwd) {
		return errors.New("旧密码验证失败!")
	}

	user.Password = util.Md5Pwd(newpwd)
	_, err = uSrv.dao.Id(uid).Cols("password").Update(user)
	if err != nil {
		return errors.Wrap(err, "更新密码失败!")
	}
	return nil
}

//给用户分配角色
func (uSrv *UserService) AddRoleForUser(userid int64, roleIds []string) error {
	session := uSrv.dao.NewSession()
	defer session.Close()
	if err := session.Begin(); err != nil {
		return errors.Wrap(err, "开启事务失败!")
	}

	_, err1 := session.SQL("delete from role_user where userid=?", userid).Execute()
	if err1 != nil {
		session.Rollback()
		return errors.Wrap(err1, "删除用户角色失败!")
	}
	if insertSQL := uSrv.getRoleUserSql(userid, roleIds); len(insertSQL) > 0 {
		_, err := session.Sql(insertSQL).Execute()
		if err != nil {
			session.Rollback()
			return errors.Wrap(err, "保存关联角色失败!")
		}
	}
	err := session.Commit()
	if err != nil {
		return errors.Wrap(err, "提交事务失败!")
	}
	util.AddRolesForUser(uSrv.ce, userid, roleIds)
	return nil
}

//获取插入role_user表SQL
func (uSrv *UserService) getRoleUserSql(userid int64, roleIds []string) string {
	if len(roleIds) <= 0 {
		return ""
	}

	var insertSQL = "insert into role_user(roleid,userid) values"
	var uidStr = strconv.FormatInt(userid, 10)
	for _, v := range roleIds {
		insertSQL += "('" + v + "','" + uidStr + "'),"
	}

	insertSQL = insertSQL[0 : len(insertSQL)-1]
	return insertSQL
}
